package cn.tedu._03vehicle.base.interceptors;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentHashMap;

public class RateLimitInterceptor implements HandlerInterceptor {
    private static final int MAX_REQUESTS_RER_MINUTE = 100;  //每分钟最大请求次数
    private static final int WINDOW_SIZE_SECONDS = 60;  //时间窗口

    //{"192.168.1.11":1,"192.168.1.12":1,"192.168.1.13":2}
    private final ConcurrentHashMap<String,Integer> clientCounts = new ConcurrentHashMap<>();
    //{"192.168.1.11":2025-02-06  14:00:00,... ...}
    private final ConcurrentHashMap<String, LocalDateTime> lastResetTimes = new ConcurrentHashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /*
            1.获取客户端的IP地址  192.168.1.222
            2.校验时间窗口：
                2.1  时间为null值：重置记录时间和次数；
                2.2  现在的时间大于 该IP最后一次访问的时间+60秒：重置记录时和次数
            3.访问次数+1
            4.校验次数是否超过3
                4.1  大于3：抛出异常，提示消息为访问过于频繁...
                4.2  小于等于3：放行  return true;
         */

        //1.获取客户端IP地址
        String clientId = request.getRemoteAddr();
        //2.获取该IP地址最后的重置时间
        LocalDateTime lastResetTime = lastResetTimes.get(clientId);
        //3.判断
        if(lastResetTime == null || LocalDateTime.now().isAfter(lastResetTime.plusSeconds(WINDOW_SIZE_SECONDS))){
            clientCounts.put(clientId,0);  //重置计数器
            lastResetTimes.put(clientId,LocalDateTime.now());  //重置时间
        }
        //4.访问次数+1
        Integer count = clientCounts.merge(clientId, 1, Integer::sum);
        //5.判断次数
        if(count>MAX_REQUESTS_RER_MINUTE){
            throw new RuntimeException("访问过于频繁，请稍后再试");
        }
        return true;
    }
}
